/*
 * 您可以通过将控制器命名为 AdminController 或在控制器上放置 [Admin] 属性来为 Orchard Core 仪表板创建页面。
 * 在本节中，您将学习如何向仪表板添加页面以及如何创建菜单项。
 */

using Ruitu.Edu.TrainingDemo.Permissions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Display;
using OrchardCore.ContentManagement.Records;
using OrchardCore.DisplayManagement;
using OrchardCore.DisplayManagement.ModelBinding;
using System.Collections.Generic;
using System.Threading.Tasks;
using YesSql;

namespace Ruitu.Edu.TrainingDemo.Controllers;

/// <summary>
/// 管理控制器 - 为 Orchard Core 仪表板提供管理页面
/// 
/// 主要用途：
/// - 为管理员提供内容管理界面
/// - 展示人员列表的不同排序方式
/// - 演示权限控制和内容显示管理
/// 
/// 使用场景：
/// - 管理员访问仪表板查看内容
/// - 按时间顺序查看人员列表
/// - 权限验证和内容展示
/// 
/// 设计原因：
/// - 遵循 Orchard Core 的管理控制器命名约定
/// - 提供统一的管理界面入口
/// - 实现细粒度的权限控制
/// 
/// 设计模式：
/// - 依赖注入模式：通过构造函数注入所需服务
/// - 授权模式：使用 IAuthorizationService 进行权限验证
/// - 显示模式：使用 IContentItemDisplayManager 管理内容显示
/// </summary>
// 如果您有多个管理控制器，可以随意命名它们，但在它们上放置 [Admin] 属性。
public sealed class AdminController : Controller
{
    private readonly IContentItemDisplayManager _contentItemDisplayManager;
    private readonly ISession _session;
    private readonly IAuthorizationService _authorizationService;
    private readonly IUpdateModelAccessor _updateModelAccessor;

    /// <summary>
    /// 构造函数 - 通过依赖注入初始化所需服务
    /// </summary>
    /// <param name="contentItemDisplayManager">内容项显示管理器，用于构建内容显示</param>
    /// <param name="session">数据库会话，用于数据查询</param>
    /// <param name="authorizationService">授权服务，用于权限验证</param>
    /// <param name="updateModelAccessor">模型更新访问器，用于模型绑定</param>
    public AdminController(
        IContentItemDisplayManager contentItemDisplayManager,
        ISession session,
        IAuthorizationService authorizationService,
        IUpdateModelAccessor updateModelAccessor)
    {
        _contentItemDisplayManager = contentItemDisplayManager;
        _session = session;
        _authorizationService = authorizationService;
        _updateModelAccessor = updateModelAccessor;
    }

    /// <summary>
    /// 默认管理页面 - 显示管理仪表板主页
    /// 
    /// 访问方式：在浏览器中输入默认 URL (/Ruitu.Edu.TrainingDemo/Admin/Index)，
    /// 需要管理员账户（或至少具有 AccessAdmin 权限的用户角色）。
    /// 如果是匿名用户，将自动显示登录页面。权限检查（即是否有 AccessAdmin 权限）也会自动进行。
    /// </summary>
    /// <returns>返回管理页面视图</returns>
    public IActionResult Index() => View();

    /// <summary>
    /// 显示最新人员列表 - 按创建时间降序排列
    /// 
    /// 您不必通过输入 URL 来访问下面的两个操作，因为我们为它们创建了管理菜单项！
    /// 下一站：Navigation/PersonsAdminMenu.cs
    /// </summary>
    /// <returns>返回最新人员列表视图</returns>
    public async Task<IActionResult> PersonListNewest()
    {
        // 如果用户需要特定权限才能访问管理面板上的页面（除了 AccessAdmin 权限），
        // 您需要在这里检查它。
        if (!await _authorizationService.AuthorizeAsync(User, PersonPermissions.AccessPersonListDashboard))
        {
            return Unauthorized();
        }

        // 这里没有什么特别的，只是显示最后 10 个 Person Page 内容项。
        var persons = await _session
            .Query<ContentItem, ContentItemIndex>()
            .Where(index => index.ContentType == ContentTypes.PersonPage)
            .OrderByDescending(index => index.CreatedUtc)
            .Take(10)
            .ListAsync();

        // 在 Views/Admin/PersonList.cshtml 文件中，您可以看到如何显示形状列表 (IEnumerable<dynamic>)。
        return View("PersonList", await GetShapesAsync(persons));
    }

    /// <summary>
    /// 显示最早人员列表 - 按创建时间升序排列
    /// </summary>
    /// <returns>返回最早人员列表视图</returns>
    public async Task<IActionResult> PersonListOldest()
    {
        // 验证用户是否有访问人员列表仪表板的权限
        if (!await _authorizationService.AuthorizeAsync(User, PersonPermissions.AccessPersonListDashboard))
        {
            return Unauthorized();
        }

        // 显示前 10 个 Person Page 内容项。
        var persons = await _session
            .Query<ContentItem, ContentItemIndex>()
            .Where(index => index.ContentType == ContentTypes.PersonPage)
            .OrderBy(index => index.CreatedUtc)
            .Take(10)
            .ListAsync();

        return View("PersonList", await GetShapesAsync(persons));
    }

    /// <summary>
    /// 获取内容项的显示形状 - 私有辅助方法
    /// 
    /// 注意 "SummaryAdmin" 显示类型，这是一个内置的显示类型，
    /// 专门用于在仪表板上列出项目。
    /// </summary>
    /// <param name="persons">要显示的人员内容项集合</param>
    /// <returns>返回形状集合，用于在视图中显示</returns>
    private async Task<IEnumerable<IShape>> GetShapesAsync(IEnumerable<ContentItem> persons) =>
        // 注意 "SummaryAdmin" 显示类型，这是一个内置的显示类型，专门用于在仪表板上列出项目。
        await persons.AwaitEachAsync(async person =>
            await _contentItemDisplayManager.BuildDisplayAsync(person, _updateModelAccessor.ModelUpdater, "SummaryAdmin"));
}

// 下一站：Navigation/TrainingDemoNavigationProvider.cs
